#pragma once
#include <vulkan/vulkan_raii.hpp>
#include "Core/Swapchain/LumineSwapchain.hpp"
#include "Core/Buffer/LumineBuffer.hpp"
#include "Core/Pipeline/LuminePipeline.hpp"
#include "Scene/Mesh.hpp"
#include "Constants.hpp"
namespace Lumine
{
    class LumineRenderer
    {
    private:
        vk::raii::CommandPool m_commandPool = nullptr;
        std::vector<vk::raii::CommandBuffer> m_commandBuffers;

        // 同步对象
        uint32_t currentFrame = 0;
        uint32_t currentImage = 0;
        std::vector<vk::raii::Semaphore> imageAvailableSemaphores;
        std::vector<vk::raii::Semaphore> renderFinishedSemaphores;
        std::vector<vk::raii::Fence> inFlightFences;

        vk::raii::DescriptorPool descriptorPool = nullptr;
        std::vector<vk::raii::DescriptorSet> descriptorSets;

        LumineSwapchain *m_swapchainRef = nullptr;
        LuminePipeline *m_pipelineRef = nullptr;
        vk::raii::Pipeline m_pipeline = nullptr;

        void createCommandPool();

        void createCommandBuffers();

        void createSyncObjects();

        void createDescriptorPool();

        void createDescriptorSets();

        vk::raii::CommandBuffer beginSingleTimeCommands();

        void endSingleTimeCommands(vk::raii::CommandBuffer &commandBuffer);

        void recordCommandBuffer(vk::raii::CommandBuffer &cmdBuffer, uint32_t imageIndex);

        void transition_image_layout(vk::raii::CommandBuffer &cmdBuffer,
                                     uint32_t imageIndex,
                                     vk::ImageLayout oldLayout,
                                     vk::ImageLayout newLayout,
                                     vk::AccessFlags2 srcAccessMask,
                                     vk::AccessFlags2 dstAccessMask,
                                     vk::PipelineStageFlags2 srcStageMask,
                                     vk::PipelineStageFlags2 dstStageMask);

    public:
        LumineRenderer() = default;

        void Initialize(LumineSwapchain &swapchain, LuminePipeline &pipeline);

        void setPipeline(vk::raii::Pipeline &&pipeline) { m_pipeline = std::move(pipeline); }

        vk::Result drawFrame();

        void copyBuffer(vk::raii::Buffer &srcBuffer, vk::raii::Buffer &dstBuffer, vk::DeviceSize size);

        void updateUniformBuffer(uint32_t currentImage);

        void recreateCommandBuffers();
    };
}